
local jass = require 'jass.common'
local japi = require 'jass.japi'
local dbg = require 'jass.debug'
local unit = require 'types.unit'
local player = require 'types.player'
local damage = require 'types.damage'
local slk = require 'jass.slk'
local math = math
local super = unit

---@class hero:unit
local hero = class('hero', unit)

hero.unit_type = '英雄'                     --类型
hero.xp = 0                                 --当前经验值
hero.response_idle_time = -99999            --下句英雄回应的最早时间
hero.skill_datas = {}                       --英雄技能数据
hero.hero_list = {
    {'小悟空', '小悟空'},
    --{'御坂美琴', '御坂美琴'},
    --{'黑雪姬', '黑雪姬'},
    --{'鹿目圆香', '鹿目圆香'},
    --{'更木剑八', '更木剑八'},
    --{'桐人', '桐人'},
    --{'夏娜', '夏娜'},
    --{'博丽灵梦', '博丽灵梦'},
    --{'魔理沙', '魔理沙'},
    --{'十六夜咲夜', '十六夜咲夜'},
    --{'丹特丽安', '丹特丽安'},
    --{'立华奏', '立华奏'},
    --{'金木研', '金木研'},
    --{'时崎狂三', '时崎狂三'},
    --{'四糸乃', '四糸乃'},
    --{'五河琴里', '五河琴里'},
    --{'夜刀神十香', '夜刀神十香'},
    --{'爱丽莎', '爱丽莎'},
    --{'亚丝娜', '亚丝娜'},
    --{'夜夜', '夜夜'},
    --{'楪祈', '楪祈'},
    --{'赤瞳', '赤瞳'},
    --{'漩涡鸣人', '漩涡鸣人'},
    --{'阿尔托莉亚', '阿尔托莉亚'},
    --{'惠惠', '惠惠'},
    --{'玉置亚子', '玉置亚子'},
    --{'岛风', '岛风'},
    --{'缇娜', '缇娜'},
    --{'索隆', '索隆'},
}

function hero:ctor(data)
	self:init(data)
end

function hero:init(data)
	if data then
		for k, v in pairs(data) do
			self[k] = v
		end
		--注册技能
		data.skill_datas = {}
		if type(data.skill_names) == 'string' then
			for name in data.skill_names:gmatch '%S+' do
				table.insert(data.skill_datas, ac.skill[name])
			end
		elseif type(data.skill_names) == 'table' then
			for _, name in ipairs(data.skill_names) do
				table.insert(data.skill_datas, ac.skill[name])
			end
		end
		self.skill_datas = data.skill_datas
	end
end

function hero:__tostring()
    local player = self:get_owner()
    return ('%s|%s|%s'):format('hero', self:get_name(), player.base_name)
end

--复活英雄
function hero:revive(where)
	if self:is_alive() then
		return
	end
	if not where then
		where = self:getBornPoint()
	end
	local origin = self:get_point()
	--print('正在复活', self:get_name())
	jass.ReviveHero(self.handle, where:get_point():get())
	self:set('生命', self:get '生命上限')
	self._is_alive = true
	self:get_owner():selectUnit(self)
	if self.wait_to_transform_id then
		local target = self.wait_to_transform_id
		self.wait_to_transform_id = nil
		self:transform(target)
	end
	for it in self:each_skill '物品' do
		if it._wait_fresh_item then
			it._wait_fresh_item = nil
			it:fresh_item()
		end
	end
	self:event_notify('单位-复活', self)
	self:event_notify('单位-传送完成', self, origin, where)
end

--获得经验值
function hero:addXp(xp)
	jass.SetHeroXP(self.handle, jass.GetHeroXP(self.handle) + xp, true);
	self.xp = jass.GetHeroXP(self.handle);
end

-- 变身
local dummy
function hero:transform(target_id)
	if not self:is_alive() then
		--死亡状态无法变身
		self.wait_to_transform_id = target_id
		return
	end

	--获取攻击间隔
	local attack_cool = self:get '攻击间隔'
	if not dummy then
		dummy = ac.dummy
		dummy:add_ability 'AEme'
	end
	--变身
	japi.EXSetAbilityDataInteger(japi.EXGetUnitAbility(dummy.handle, base.string2id 'AEme'), 1, 117, base.string2id(self:get_type_id()))
	self:add_ability 'AEme'
	japi.EXSetAbilityAEmeDataA(japi.EXGetUnitAbility(self.handle, base.string2id 'AEme'), base.string2id(target_id))
	self:remove_ability 'AEme'

	--修改ID
	self.id = target_id

	--恢复攻击距离
	self.default_attack_range = nil
	self:add('攻击范围', 0)

	--恢复攻击力
	self:add('攻击', 0)

	--恢复移动速度
	self:add('移动速度', 0)

	--恢复攻击间隔
	self:add('攻击间隔', 0)

	--可以飞行
	self:add_ability 'Arav'
	self:remove_ability 'Arav'
	self:set_high(self:get_high())

	--动画混合时间
	jass.SetUnitBlendTime(self.handle, self:get_slk('blend', 0))

    -- 恢复特效
    if self._effect_list then
        for _, eff in ipairs(self._effect_list) do
            if eff.handle then
                jass.DestroyEffect(eff.handle)
                dbg.handle_unref(eff.handle)
                eff.handle = jass.AddSpecialEffectTarget(eff.model, self.handle, eff.socket or 'origin')
                dbg.handle_ref(eff.handle)
            end
        end
    end
end

--获得属性
function hero:getStr()
	return jass.GetHeroStr(self.handle, true)
end

function hero:getAgi()
	return jass.GetHeroAgi(self.handle, true)
end

function hero:getInt(self)
	return jass.GetHeroInt(self.handle, true)
end

--设置属性
function hero:setStr(n)
	jass.SetHeroStr(self.handle, n, true)
end

function hero:setAgi(n)
	jass.SetHeroAgi(self.handle, n, true)
end

function hero:setInt(n)
	jass.SetHeroInt(self.handle, n, true)
end

--添加全部技能
function hero:add_all_hero_skills()
	local t = {}
	for i = 1, #self.skill_datas do
		local skl = self.skill_datas[i]
		if i > 4 then
			t[i] = self:find_skill(i, '隐藏', true) or self:add_skill(skl.name, '隐藏', i, {level = 0})
		else
			t[i] = self:find_skill(i, '英雄', true) or self:add_skill(skl.name, '英雄', i, {level = 0})
		end
	end
	for i = 1, #t do
		local level = self.skill_datas[i].level
		t[i]:set_level(level)
	end
end

--刷新伤害属性信息
function hero:freshDamageInfo()
	local atk = self:get '攻击'
	local pene, pener = self:get '破甲', self:get '穿透'
	local crit, critr = self:get '暴击', self:get '暴击伤害'
	local crit_up = crit * (critr/100 - 1) / 100 + 1
	local damage = atk * crit_up * (self:getDamageRate() / 100.0) * 60
	self:setStr(damage)
	return damage
end

--刷新坚韧属性信息
function hero:freshDefenceInfo()
	local life = self:get '生命上限'
	local def = self:get '护甲'
	local damaged_rate = self:getDamagedRate()
	local block_chance, block_rate = self:get '格挡', self:get '格挡伤害'
	if block_chance > 100 then block_chance = 100 end
	if block_rate > 100 then block_rate = 100 end
	local def_up = 1
	if def > 0 then
		def_up = 1 + def * damage.DEF_SUB
	else
		def_up = 1 / (1 - def * damage.DEF_ADD)
	end
	local block_up = 1 / (1.0 - block_chance * block_rate / 10000.0)
	local defence = life * def_up * block_up
	if damaged_rate > 5 then
		defence = defence * 100.0 / damaged_rate
	end
	self:setAgi(defence)
	return defence
end

--刷新移动速度信息
function hero:freshMoveSpeedInfo()
	self:setInt(math.max(0, self:get('移动速度')))
end

--修改英雄技能点数
function hero:addSkillPoint(points)
	self.skill_points = self.skill_points + points
	local skl = self:find_skill('技能升级', nil, true)
	if not skl then
		return
	end
	skl:call_updateSkillPoint()
end

function hero:get_ad()
	return self:get '攻击'
end

function hero.create(name)
    return function(data)
        return g_heroMgr:create_hero(name, data)
    end
end

function hero:hasItem(itemId)
    local ret = true
    --local abilityId = GameEnum.Ability.ABILITY_CHOOSE_HERO
    --local lv = self:getAbilityLevel(abilityId) print("lv ", abilityId, lv)
    --if lv <= 0 then
    --    ret = false
    --    return ret
    --end

    local items = {}
    if type(itemId) == 'number' then
        table.insert(items, itemId)
    end

    local containItems = {}
    for i = 0, 5 do
        local it = jass.UnitItemInSlot(self.handle, i)
        if it ~= 0 then
            local item_type_str = base.id2string(jass.GetItemTypeId(it))
            table.insert(containItems, item_type_str)
        end
    end

    for i, v in ipairs(items) do
        if not array.contains(containItems, v) then
            ret = false
            break
        end
    end
    return ret
end

--==============================--
--@Description:添加道具
--@Date: 2018/12/30
--@Param: [args]
--@Return:
--==============================--
function hero:add_item(itemId)
    local newit = jass.CreateItem(base.string2id(itemId), jass.GetUnitX(hero.handle), jass.GetUnitY(hero.handle))
    dbg.handle_ref(newit)
    jass.UnitAddItem(self.handle, newit)
end

--==============================--
--@Description:根据item str删除背包中的道具
--@Date: 2018/12/30
--@Param: [args]
--@Return:
--==============================--
function hero:remove_item(itemId)
    local function _remove(itemHandle)
        local charges = jass.GetItemCharges(itemHandle)
        if charges > 1 then
            jass.SetItemCharges(itemHandle, charges - 1)
        else
            jass.RemoveItem(itemHandle)
            dbg.handle_unref(itemHandle)
        end
    end
    for i = 0, 5 do
        local it = jass.UnitItemInSlot(self.handle, i)
        if it ~= 0 then
            local item_type_str = base.id2string(jass.GetItemTypeId(it))
            if itemId == item_type_str then
                _remove(it)
                break
            end
        end
    end
end

function hero:is_bag_full()
	local ret = true
	for i = 0, 5 do
		local it = jass.UnitItemInSlot(self.handle, i)
		if it == 0 then
			ret = false
			break
		end
	end
	return ret
end

ac.hero = hero

return hero
